package com.sky.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.properties.BaiduProperties;
import com.sky.properties.ShopProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Component
public class BaiduMapUtils {

    private final BaiduProperties baiduProperties;
    private final ShopProperties shopProperties;

    // 配送范围（米）
    private static final int DELIVERY_RANGE = 5000;

    @Autowired
    public BaiduMapUtils(BaiduProperties baiduProperties, ShopProperties shopProperties) {
        this.baiduProperties = baiduProperties;
        this.shopProperties = shopProperties;
    }

    /**
     * 校验配送距离是否在范围内
     */
    public boolean checkDeliveryRange(String userAddress) {
        try {
            // 先进行地址解析，获取经纬度坐标
            String shopLocation = geocodeAddress(shopProperties.getAddress());
            String userLocation = geocodeAddress(userAddress);

            if (shopLocation == null || userLocation == null) {
                log.error("地址解析失败: shop={}, user={}", shopProperties.getAddress(), userAddress);
                return false;
            }

            double distance = calculateDistance(shopLocation, userLocation);
            log.info("配送距离: {}米, 商家: {}, 用户: {}", distance, shopProperties.getAddress(), userAddress);
            return distance <= DELIVERY_RANGE;
        } catch (Exception e) {
            log.error("计算配送距离失败", e);
            return false;
        }
    }

    /**
     * 地址解析（地理编码）- 将地址转换为经纬度坐标
     */
    private String geocodeAddress(String address) throws Exception {
        String url = "https://api.map.baidu.com/geocoding/v3/?";

        Map<String, String> params = new LinkedHashMap<>();
        params.put("address", address);
        params.put("output", "json");
        params.put("ak", baiduProperties.getAK());
        params.put("timestamp", String.valueOf(Instant.now().getEpochSecond())); // 添加时间戳

        // 计算SN校验
        String sn = calculateSn(params, "/geocoding/v3/");
        params.put("sn", sn);

        String response = requestGet(url, params);

        JSONObject jsonResponse = JSON.parseObject(response);
        if (jsonResponse.getInteger("status") == 0) {
            JSONObject location = jsonResponse.getJSONObject("result").getJSONObject("location");
            return location.getString("lat") + "," + location.getString("lng");
        } else {
            log.error("地址解析失败: {}, response: {}", address, response);
            return null;
        }
    }

    /**
     * 计算两个坐标点之间的距离（米）
     */
    private double calculateDistance(String origin, String destination) throws Exception {
        String url = "https://api.map.baidu.com/directionlite/v1/driving?";

        Map<String, String> params = new LinkedHashMap<>();
        params.put("origin", origin);
        params.put("destination", destination);
        params.put("ak", baiduProperties.getAK());
        params.put("timestamp", String.valueOf(Instant.now().getEpochSecond())); // 添加时间戳

        // 计算SN校验
        String sn = calculateSn(params, "/directionlite/v1/driving");
        params.put("sn", sn);

        String response = requestGet(url, params);
        return parseDistanceFromResponse(response);
    }

    /**
     * 解析响应中的距离
     */
    private double parseDistanceFromResponse(String response) {
        try {
            JSONObject jsonResponse = JSON.parseObject(response);
            if (jsonResponse.getInteger("status") == 0) {
                JSONObject result = jsonResponse.getJSONObject("result");
                JSONObject route = result.getJSONArray("routes").getJSONObject(0);
                return route.getDouble("distance"); // 返回距离（米）
            } else {
                log.error("距离计算失败: {}", response);
                throw new RuntimeException("距离计算失败: " + jsonResponse.getString("message"));
            }
        } catch (Exception e) {
            log.error("解析距离响应失败: {}", response, e);
            throw new RuntimeException("解析距离失败", e);
        }
    }

    /**
     * 发送GET请求（通用方法）
     */
    private String requestGet(String strUrl, Map<String, String> param) throws Exception {
        StringBuilder queryString = new StringBuilder(strUrl);
        for (Map.Entry<String, String> pair : param.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            queryString.append(UriUtils.encode(pair.getValue(), "UTF-8")).append("&");
        }

        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }

        log.info("请求百度地图API: {}", queryString.toString());

        URL url = new URL(queryString.toString());
        HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
        httpConnection.setRequestMethod("GET");
        httpConnection.setConnectTimeout(5000);
        httpConnection.setReadTimeout(5000);

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(httpConnection.getInputStream()))) {
            StringBuilder buffer = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            String response = buffer.toString();
            log.info("百度地图API响应: {}", response);
            return response;
        } finally {
            httpConnection.disconnect();
        }
    }

    /**
     * 计算SN签名
     */
    private String calculateSn(Map<String, String> params, String urlPath)
            throws UnsupportedEncodingException, NoSuchAlgorithmException {

        // 构建查询字符串（保持LinkedHashMap的顺序）
        String paramsStr = toQueryString(params);

        // 拼接完整字符串：API路径 + ? + 查询字符串 + SK
        String wholeStr = urlPath + "?" + paramsStr + baiduProperties.getSK();

        log.debug("SN计算原始字符串: {}", wholeStr);

        // 对整个字符串进行URL编码
        String tempStr = URLEncoder.encode(wholeStr, "UTF-8");

        // MD5加密
        return MD5(tempStr);
    }

    /**
     * 生成查询字符串
     */
    private String toQueryString(Map<String, String> data) throws UnsupportedEncodingException {
        StringBuilder queryString = new StringBuilder();
        for (Map.Entry<String, String> pair : data.entrySet()) {
            if (queryString.length() > 0) {
                queryString.append("&");
            }
            queryString.append(pair.getKey()).append("=");
            queryString.append(UriUtils.encode(pair.getValue(), "UTF-8"));
        }
        return queryString.toString();
    }

    /**
     * MD5计算方法
     */
    private String MD5(String md5) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(md5.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < array.length; ++i) {
                sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("MD5加密失败", e);
            return null;
        }
    }

    /**
     * 简化版距离计算（如果API调用失败时使用）
     */
    public double calculateSimpleDistance(String userAddress) {
        try {
            // 这里使用简化的距离估算
            // 实际项目中可以根据具体需求实现更精确的计算
            log.warn("使用简化距离计算，地址: {}", userAddress);

            // 返回一个默认在配送范围内的距离（比如3公里）
            return 3000;
        } catch (Exception e) {
            log.error("简化距离计算失败", e);
            return DELIVERY_RANGE - 1000; // 返回一个在配送范围内的值
        }
    }

    /**
     * 改进的配送范围校验（带降级方案）
     */
    public boolean checkDeliveryRangeWithFallback(String userAddress) {
        try {
            // 先尝试使用百度API
            String shopLocation = geocodeAddress(shopProperties.getAddress());
            String userLocation = geocodeAddress(userAddress);

            if (shopLocation == null || userLocation == null) {
                log.warn("地址解析失败，使用简化计算");
                double distance = calculateSimpleDistance(userAddress);
                return distance <= DELIVERY_RANGE;
            }

            double distance = calculateDistance(shopLocation, userLocation);
            log.info("配送距离: {}米", distance);
            return distance <= DELIVERY_RANGE;

        } catch (Exception e) {
            log.error("百度地图API调用失败，使用简化计算", e);
            // 降级方案：使用简化距离计算
            double distance = calculateSimpleDistance(userAddress);
            return distance <= DELIVERY_RANGE;
        }
    }
}